//
//  TPButton.m
//  Pods
//
//  Created by caixun on 15/11/3.
//
//

#import "TPButton.h"
#import "SDWebImageManager.h"
#import "UIView+WebCacheOperation.h"


/// 是否为NSString类型（单独处理NSMutableString）
#define TP_Str_Class(str) [str isKindOfClass:[NSString class]]
#define TP_mStr_Class(mstr) [mstr isKindOfClass:[NSMutableString class]]

/// 是否有效，不为空，且是NSString类型，且count值大于0（单独处理NSMutableString）
#define TP_Str_Is_Valid(str) ((str) && (TP_Str_Class(str)) && ([str length] > 0))
#define TP_mStr_Is_Valid(mstr) ((mstr) && (TP_mStr_Class(mstr)) && ([mstr length] > 0))

/// 是否无效，或为空，或不是NSString类型，或count值小于等于0（单独处理NSMutableString）
#define TP_Str_Not_Valid(str) ((!str) || (!TP_Str_Class(str)) || ([str length] <= 0))
#define TP_mStr_Not_Valid(mstr) ((!mstr) || (!TP_mStr_Class(mstr)) || ([mstr length] <= 0))

/// 格式化字符串
#define TP_Str_Format(...) [NSString stringWithFormat:__VA_ARGS__]

/// nil保护，当为nil时，返回@""，避免一些Crash
#define TP_Str_Protect(str) ((str) ? (str) : (@""))


@interface TPButton ()


/// 下载后是否显示消失动画效果，YES表示显示动画，暂不对外开放
@property (nonatomic, assign) BOOL isShowDismissAnimated;
/// 动画展示时间
@property (nonatomic, assign) CGFloat fltAnimDuration;
/// 默认图片
@property (nonatomic, strong) UIImage *imgPlaceholder;
/// 下载错误时显示的图片
@property (nonatomic, strong) UIImage *imgError;
/// 是否显示占位图片
@property (nonatomic, assign) BOOL isShowPlaceholderImg;


@end


@implementation TPButton


#pragma mark - *********************************** View Lifecycle **********************************

/*!
 *  @author caixun, 15-11-03 11:11:21
 *
 *  @brief  只重写此方法，经过测试，调用init方法时会自动调用initWithFrame方法
 *
 *  @param frame btn的frame
 *
 *  @return 返回创建好的btn对象
 *
 *  @since v1.0
 */
- (instancetype)initWithFrame:(CGRect)frame
{
    if (self = [super initWithFrame:frame])
    {
        // 设置公共属性，与APP的UI规范 无关
        [self setCommonAttribute];
    }
    
    return self;
}

/*!
 *  @author caixun, 15-11-03 11:11:47
 *
 *  @brief  设置公共属性，与APP的UI规范 无关
 *
 *  @since v1.0
 */
- (void)setCommonAttribute
{
    if (self)
    {
        self.backgroundColor = [UIColor clearColor];
        
        self.opaque = YES;
        
        // 禁止多个Button同时响应点击事件
        self.exclusiveTouch = YES;
        
        // 在某些设备上可能会出现像素点显示不均匀的情况，设置该属性将超出bounds范围的剪切掉
        self.clipsToBounds = YES;
    }
}

/*!
 *  @author caixun, 15-11-03 11:11:11
 *
 *  @brief  初始化变量
 *
 *  @since v1.0
 */
- (void)initVariable
{
    /// 需求要求下载图片时无动画效果
    _isShowDismissAnimated = NO;
    
    /// 默认显示占位图
    _isShowPlaceholderImg = YES;
    
    /// 默认时间为0.5秒
    _fltAnimDuration = 0.5;
    
    /// 默认是图片显示到image上
    _isSetBgImg = NO;
}

- (void)dealloc
{
    [self cancelCurrentImageLoad];
}


#pragma mark - ********************************** 初始化方法 工厂方法 *********************************

/*!
 *  @author caixun, 15-11-03 11:11:31
 *
 *  @brief  初始化基本设置
 *
 *  @param frame 按钮的frame
 *
 *  @return 返回创建好的按钮对象
 *
 *  @since v1.0
 */
+ (instancetype)getWithFrame:(CGRect)frame
{
    TPButton *btn = [[self alloc] initWithFrame:frame];
    
    return btn;
}

/*!
 *  @author caixun, 15-11-03 11:11:53
 *
 *  @brief  初始化按钮
 *
 *  @param frame  按钮的frame
 *  @param target 按钮事件响应对象
 *  @param action 按钮事件的触发函数
 *
 *  @return 返回创建好的按钮
 *
 *  @since v1.0
 */
+ (instancetype)getWithFrame:(CGRect)frame target:(id)target action:(SEL)action
{
    TPButton *btn = [[self alloc] initWithFrame:frame];
    
    /// 设置响应事件
    [btn addTarget:target action:action forControlEvents:UIControlEventTouchUpInside];
    
    return btn;
}


#pragma mark - ********************************** 初始化方法 实例方法 *********************************

/*!
 *  @author caixun, 15-11-03 11:11:03
 *
 *  @brief  初始化基本设置
 *
 *  @param frame  按钮的frame
 *  @param target 响应按钮点击事件的对象
 *  @param action 按钮事件的触发函数
 *
 *  @return 返回创建好的按钮
 *
 *  @since v1.0
 */
- (instancetype)initWithFrame:(CGRect)frame target:(id)target action:(SEL)action
{
    if (self = [self initWithFrame:frame])
    {
        /// 设置响应事件
        [self addTarget:target action:action forControlEvents:UIControlEventTouchUpInside];
    }
    
    return self;
}


#pragma mark - *********************************** 设置属性 实例方法 **********************************

/*!
 *  @author caixun, 15-11-03 11:11:42
 *
 *  @brief  设置target和action
 *
 *  @param target 响应按钮点击事件的对象
 *  @param action 按钮事件的触发函数
 *
 *  @since v1.0
 */
- (void)setTarget:(id)target action:(SEL)action
{
    if (self)
    {
        [self addTarget:target action:action forControlEvents:UIControlEventTouchUpInside];
    }
}

/*!
 *  @author caixun, 15-11-03 11:11:03
 *
 *  @brief  设置Image
 *
 *  @param imgNor 默认状态下按钮的图片
 *
 *  @since v1.0
 */
- (void)setNorImg:(UIImage *)imgNor
{
    if (self)
    {
        [self setImage:imgNor forState:UIControlStateNormal];
    }
}

/*!
 *  @author caixun, 15-11-03 11:11:25
 *
 *  @brief  设置BgImage
 *
 *  @param imgBgNor 默认状态下按钮的背景图片
 *
 *  @since v1.0
 */
- (void)setNorBgImg:(UIImage *)imgBgNor
{
    if (self)
    {
        [self setBackgroundImage:imgBgNor forState:UIControlStateNormal];
    }
}

/*!
 *  @author caixun, 15-11-03 11:11:44
 *
 *  @brief  同时设置BgImage和Title
 *
 *  @param imgBgNor      默认状态下按钮的背景图片
 *  @param strNorTitle   默认状态下按钮的文字
 *  @param colorNorTitle 默认状态下按钮的文字颜色
 *  @param fontTitle     默认状态下按钮的字体
 *
 *  @since v1.0
 */
- (void)setNorBgImg:(UIImage *)imgBgNor
           norTitle:(NSString *)strNorTitle
      norTitleColor:(UIColor *)colorNorTitle
          titleFont:(UIFont *)fontTitle
{
    if (self)
    {
        [self setBackgroundImage:imgBgNor forState:UIControlStateNormal];
        [self setTitle:strNorTitle forState:UIControlStateNormal];
        [self setTitleColor:colorNorTitle forState:UIControlStateNormal];
        self.titleLabel.font = fontTitle;
    }
}

/*!
 *  @author caixun, 15-11-03 11:11:38
 *
 *  @brief  设置圆角，边框
 *
 *  @param fltCornerRadius 圆角的角度
 *  @param fltBorderWidth  边框宽度
 *  @param colorBorder     边框的颜色
 *
 *  @since v1.0
 */
- (void)setCornerRadius:(CGFloat)fltCornerRadius
            borderWidth:(CGFloat)fltBorderWidth
            borderColor:(UIColor *)colorBorder
{
    if (self)
    {
        self.layer.cornerRadius = fltCornerRadius;
        self.layer.borderColor = colorBorder.CGColor;
        
        /// 根据屏幕的分辨率倍数适配边框宽度
        self.layer.borderWidth = [self scaleAdaptWidth:fltBorderWidth];
    }
}


#pragma mark - ************************************ 动态加载图片URL **********************************

/*!
 *  @author caixun, 15-11-03 11:11:49
 *
 *  @brief  设置是否显示占位图片,默认为YES
 *
 *  @param isShowPlaceholderImg 按钮是否显示缺省图片
 *
 *  @since v1.0
 */
- (void)setIsShowPlaceholderImg:(BOOL)isShowPlaceholderImg
{
    _isShowPlaceholderImg = isShowPlaceholderImg;
}

/*!
 *  @author caixun, 15-11-03 11:11:16
 *
 *  @brief  设置默认图片
 *
 *  @param imgPlaceholder 按钮的缺省图片
 *
 *  @since v1.0
 */
- (void)setPlaceholderImage:(UIImage *)imgPlaceholder
{
    /// 图片存在且是UIimage类型
    if (imgPlaceholder && [imgPlaceholder isKindOfClass:[UIImage class]])
    {
        /// 保存默认图片
        _imgPlaceholder = imgPlaceholder;
    }
}

#pragma mark - 下载图片，delegate形式

/*!
 *  @author caixun, 15-11-03 11:11:33
 *
 *  @brief  设置网络图片Url
 *
 *  @param strImgUrl 图片的url
 *
 *  @since v1.0
 */
- (void)setImageURL:(NSString *)strImgUrl
{
    [self setImageURL:strImgUrl options:0];
}

/*!
 *  @author caixun, 15-11-03 11:11:47
 *
 *  @brief  下载图片，异步方式
 *
 *  @param strImgUrl 按钮图片的url
 *  @param options
 *
 *  @since v1.0
 */
- (void)setImageURL:(NSString *)strImgUrl options:(SDWebImageOptions)options
{
    /// 下载之前显示默认图片（按钮默认状态下）
    if (_isShowPlaceholderImg)
    {
        if (_isSetBgImg) /// 判断是设置成背景图片还是普通图片
        {
            [self setBackgroundImage:_imgPlaceholder forState:UIControlStateNormal];
        }
        else
        {
            [self setImage:_imgPlaceholder forState:UIControlStateNormal];
        }
    }
    
    /// 移除之前下载队列
    [self cancelCurrentImageLoad];
    
    /// 获取img的URL
    NSURL *urlImg = [self changeImageUrl:strImgUrl];
    
    /// 加载网络图片
    if (([urlImg isKindOfClass:[NSURL class]]))
    {
        SDWebImageManager *manager = [SDWebImageManager sharedManager];
        
        __weak typeof(self) weakSelf = self;
        id <SDWebImageOperation> operation = [manager downloadImageWithURL:urlImg
                                                                   options:options
                                                                  progress:nil
                                                                 completed:^(UIImage *image,
                                                                             NSError *error,
                                                                             SDImageCacheType cacheType,
                                                                             BOOL finished,
                                                                             NSURL *imageURL)
          {
              if (!weakSelf) return;
              
              if (finished && !error)
              {
                  [weakSelf didFinishWithImage:image];
              }
              else if (finished && error)
              {
                  [weakSelf didFailWithError:error];
              }
              else if (!finished)
              {
                  if (options & SDWebImageProgressiveDownload)
                  {
                      if (image)
                      {
                          /// 判断是否为背景图
                          if (_isSetBgImg)
                          {
                              [weakSelf setBackgroundImage:image forState:UIControlStateNormal];
                          }
                          else
                          {
                              [weakSelf setImage:image forState:UIControlStateNormal];
                          }
                          [weakSelf setNeedsLayout];
                      }
                      else
                      {
                          if (_isSetBgImg)
                          {
                              [weakSelf setBackgroundImage:_imgError forState:UIControlStateNormal];
                          }
                          else
                          {
                              [weakSelf setImage:_imgError forState:UIControlStateNormal];
                          }
                          [weakSelf setNeedsLayout];
                      }
                  }
              }
          }];
        
        [self sd_setImageLoadOperation:operation forKey:@"UIImageViewImageLoad"];
    }
}

#pragma mark - 下载图片，Block形式

/*!
 *  @author caixun, 15-11-03 11:11:32
 *
 *  @brief  加载网络图片，设置成功和失败Block回调
 *
 *  @param strImgUrl 按钮网络图片的地址
 *  @param success   成功回调
 *  @param failure   失败回调
 *
 *  @since v1.0
 */
- (void)setImageURL:(NSString *)strImgUrl
            success:(void (^)(UIImage *image))success
            failure:(void (^)(NSError *error))failure
{
    [self setImageURL:strImgUrl options:0 success:success failure:failure];
}

/*!
 *  @author caixun, 15-11-03 11:11:04
 *
 *  @brief  加载网络图片
 *
 *  @param strImgUrl
 *  @param options
 *  @param success
 *  @param failure
 *
 *  @since v1.0
 */
- (void)setImageURL:(NSString *)strImgUrl
            options:(SDWebImageOptions)options
            success:(void (^)(UIImage *image))success
            failure:(void (^)(NSError *error))failure;
{
    [self sd_cancelImageLoadOperationWithKey:@"UIImageViewImageLoad"];
    
    if (_isShowPlaceholderImg)
    {
        // 判断是设置成背景图片还是普通图片
        if (_isSetBgImg)
        {
            [self setBackgroundImage:_imgPlaceholder forState:UIControlStateNormal];
        }
        else
        {
            [self setImage:_imgPlaceholder forState:UIControlStateNormal];
        }
    }
    
    SDWebImageManager *manager = [SDWebImageManager sharedManager];
    // 获取img的URL
    NSURL *urlImg = [self changeImageUrl:strImgUrl];
    
    // 加载网络图片
    if ([urlImg isKindOfClass:[NSURL class]])
    {
        __weak typeof(self) weakSelf = self;
        
        id <SDWebImageOperation> operation = [manager downloadImageWithURL:urlImg
                                                                   options:options
                                                                  progress:nil
                                                                 completed:^(UIImage *image,
                                                                             NSError *error,
                                                                             SDImageCacheType cacheType,
                                                                             BOOL finished,
                                                                             NSURL *imageURL)
          {
              if (!weakSelf) return;
              
              if (finished && !error)
              {
                  if (!(options & SDWebImageProgressiveDownload))
                  {
                      [weakSelf didFinishWithImage:image];
                  }
                  
                  if (success)
                  {
                      success(image);
                  }
              }
              else if (finished && error)
              {
                  [weakSelf didFailWithError:error];
                  if (failure)
                  {
                      failure(error);
                  }
              }
              else if (!finished)
              {
                  if (options & SDWebImageProgressiveDownload)
                  {
                      if (image)
                      {
                          /// 判断是否为背景图
                          if (_isSetBgImg)
                          {
                              [weakSelf setBackgroundImage:image forState:UIControlStateNormal];
                          }
                          else
                          {
                              [weakSelf setImage:image forState:UIControlStateNormal];
                          }
                          [weakSelf setNeedsLayout];
                      }
                      else
                      {
                          if (_isSetBgImg)
                          {
                              [weakSelf setBackgroundImage:_imgError forState:UIControlStateNormal];
                          }
                          else
                          {
                              [weakSelf setImage:_imgError forState:UIControlStateNormal];
                          }
                          [weakSelf setNeedsLayout];
                      }
                  }
              }
          }];
        
        [self sd_setImageLoadOperation:operation forKey:@"UIImageViewImageLoad"];
    }
}

#pragma mark - ************************************* Functions *************************************

/*!
 *  @author caixun, 15-11-03 11:11:47
 *
 *  @brief  是否显示图片（有图模式）
 *
 *  @return
 *
 *  @since v1.0
 */
- (BOOL)shouldShowImage
{
    // 这个地方日后可以设置一个全局变量，作为整个app是否下载图片的一个标示位
    return YES;
}

/*!
 *  @author caixun, 15-11-03 11:11:48
 *
 *  @brief  取消当前图片下载
 *
 *  @since v1.0
 */
- (void)cancelCurrentImageLoad
{
    [self sd_cancelImageLoadOperationWithKey:@"UIImageViewImageLoad"];
}

/*!
 *  @author caixun, 15-11-03 11:11:57
 *
 *  @brief  将图片URL从NSString格式转换NSUrl格式
 *
 *  @param strImgUrl 按钮图片地址的字符串格式
 *
 *  @return 地址的url格式
 *
 *  @since v1.0
 */
- (NSURL *)changeImageUrl:(NSString *)strImgUrl
{
    /// 无图片模式，直接返回
    if (![self shouldShowImage])
    {
        return nil;
    }
    
    /// 图片连接是为空，直接返回
    if (TP_Str_Not_Valid(strImgUrl))
    {
        return nil;
    }
    
    /// 图片链接是否正常
    if (![self tpCheckImageURL:strImgUrl])
    {
        return nil;
    }
    
    /// 对URL转码，处理URL中有汉字的情况
    strImgUrl = [strImgUrl stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
    
    /// 获取img的URL
    NSURL *urlImg = [NSURL URLWithString:strImgUrl];
    
    return urlImg;
}

/*!
 *  @author caixun, 15-11-03 11:11:54
 *
 *  @brief  淡出动画，从有到无
 *
 *  @param view
 *
 *  @since v1.0
 */
- (void)animationEaseOut:(UIView *)view
{
    view.alpha = 1.0;
    [UIView beginAnimations:nil context:NULL];
    [UIView setAnimationDuration:_fltAnimDuration];
    view.alpha = 0.0;
    [UIView commitAnimations];
}

/*!
 *  @author caixun, 15-11-03 11:11:43
 *
 *  @brief  淡入动画，从无到有
 *
 *  @param view
 *
 *  @since v1.0
 */
- (void)animationEaseIn:(UIView *)view
{
    view.alpha = 0.0;
    [UIView beginAnimations:nil context:NULL];
    [UIView setAnimationDuration:_fltAnimDuration];
    view.alpha = 1.0;
    [UIView commitAnimations];
}

- (CGFloat)scaleAdaptWidth:(CGFloat)fltWidth
{
    /// 如果宽度为0，则直接返回
    if (fltWidth == 0)
    {
        return fltWidth;
    }
    
    /// 获取屏幕的像素密度，如iPhone6Plus，一个点上有3个像素，该值为3
    CGFloat fltScale = [UIScreen mainScreen].scale;
    /// 传入的参数最小值要求为1，如果小于1，则设为1，保证像素最小值为1
    if (fltWidth < 1.0)
    {
        fltWidth = 1.0;
    }
    /// 要显示的点除以屏幕密度，为要返回的点，比实际传进来的要小
    return (fltScale > 0 ? (fltWidth / fltScale) : fltWidth);
}


- (BOOL)tpCheckImageURL:(NSString *)strImgUrl
{
    if (!([strImgUrl hasPrefix:@"http:"] || [strImgUrl hasPrefix:@"https:"])) /// 不是URL,直接返回NO
    {
        return NO;
    }
    
    /// 对URL转码，处理URL中有汉字的情况
    NSString *strCode = [strImgUrl stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
    
    /// 获取img的URL
    NSURL *urlImg = [NSURL URLWithString:strCode];
    
    /// 根据urlImg的path是否为空来判断是否为图片地址
    return TP_Str_Is_Valid([urlImg path]);
}


#pragma mark - *********************************** Delegate Event **********************************

/*!
 *  @author caixun, 15-11-03 11:11:08
 *
 *  @brief  图片下载成功的函数
 *
 *  @param image 按钮下载成功的图片
 *
 *  @since v1.0
 */
- (void)didFinishWithImage:(UIImage*)image
{
    /// 加入一个保护，判断是否下载完成成功
    if (!([image isKindOfClass:[UIImage class]])
        || (image.size.height <= 0))
    {
        return;
    }
    /// 判断是否为背景图
    if (_isSetBgImg)
    {
        [self setBackgroundImage:image forState:UIControlStateNormal];
    }
    else
    {
        [self setImage:image forState:UIControlStateNormal];
    }
    
    ///  是否显示消失动画
    if (self.isShowDismissAnimated)
    {
        [self animationEaseIn:self];
    }
}

/*!
 *  @author caixun, 15-11-03 11:11:47
 *
 *  @brief  按钮的图片下载失败时的函数
 *
 *  @param error 错误信息
 *
 *  @since v1.0
 */
- (void)didFailWithError:(NSError *)error
{
#ifdef DEBUG /// 测试模式下
    /// 打印错误信息
    if (error.code == 404) /// 如果是404则显示提示404错误图片
    {
#warning 等到上线的时候替换本地的错误图片
        [self setImage:[UIImage imageWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"" ofType:@"jpg"]] forState:UIControlStateNormal];
    }
    
#endif
    
    if (!_imgError || ![_imgError isKindOfClass:[UIImage class]])
    {
        return;
    }
    /// 判断图片是设置成背景图片还是普通图片
    if (_isSetBgImg)
    {
        [self setBackgroundImage:_imgError forState:UIControlStateNormal];
    }
    else
    {
        [self setImage:_imgError forState:UIControlStateNormal];
    }
    
    /// 默认不显示图片消失动画
    if (self.isShowDismissAnimated)
    {
        [self animationEaseIn:self];
    }
}


@end
